package com.zzyl.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.zzyl.constant.AdminCacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.ResourceVo;
import com.zzyl.vo.TreeItemVo;
import com.zzyl.vo.TreeVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    ResourceMapper resourceMapper;

    /**
     * 获取资源列表
     * @param resourceDto
     * @return List
     */
    @Override
    @Cacheable(cacheNames  = AdminCacheConstant.RESOURCE_LIST, key = "#resourceDto.hashCode()")
    public List<ResourceVo> resourceList(ResourceDto resourceDto) {
        List<Resource> resource = resourceMapper.resourceList(resourceDto);
        return BeanUtil.copyToList(resource, ResourceVo.class);
    }

    /**
     * 新建资源
     * @param resourceDto
     * @return Boolean
     */
    @Caching(
            evict = {
                    @CacheEvict(cacheNames  = AdminCacheConstant.RESOURCE_LIST,allEntries = true),
                    @CacheEvict(cacheNames  = AdminCacheConstant.RESOURCE_TREE,allEntries = true)
            }
    )
    @Override
    public Boolean createResource(ResourceDto resourceDto) {
        // 将dto转成实体
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        // 获取资源编号
        Resource parentResource = resourceMapper.selectByResourceNo(resourceDto.getParentResourceNo());

        // 判断是否是按钮
        if (parentResource.getResourceType().equals("r")) {
            throw new BaseException(BasicEnum.BUTTON_NOT_HAVE_CHILD);
        }

        // 父资源状态 0 启用 1 禁用
        resource.setDataState(parentResource.getDataState());

        // 资源类型 s平台 c 目录 m 菜单 r 按钮 资源的层级，支持三层
        // 如果是按钮就是false
        boolean flag = true;
        // 按钮不能有子节点
        if (StringUtils.isNotEmpty(resourceDto.getResourceType())
                && resourceDto.getResourceType().equals(SuperConstant.BUTTON)) {
            flag = false;
        }
        // 创建子编号
        String resourceNo = createResourceNo(resource.getParentResourceNo(), flag);
        // 设置资源编号
        resource.setResourceNo(resourceNo);
        // 插入
        resourceMapper.insert(resource);

        return true;
    }

    /**
     * 获取资源树
     * @param resourceDto
     * @return TreeVo
     */
    @Override
    @Cacheable(cacheNames  = AdminCacheConstant.RESOURCE_TREE)
    public TreeVo resource(ResourceDto resourceDto) {
        // 构建dto
        ResourceDto res = ResourceDto.builder().build();
        // 查询
        List<Resource> resourceList = resourceMapper.resourceList(res);

        log.info("数量为，{}", resourceList.size());

        if (resourceList == null || resourceList.size() == 0) {
            throw new RuntimeException("资源为空");
        }
        // 新建一个实体类对象
        Resource root = new Resource();
        // 把资源编号根节点
        root.setResourceNo(SuperConstant.ROOT_PARENT_ID);
        // 把根节点名称传入进去
        root.setResourceName("智慧养老");
        // 新建一个集合
        List<TreeItemVo> itemsvo = new ArrayList<>();
        // 递归
        recursionTreeItem(itemsvo, root, resourceList);

        // 封装
        TreeVo treeVo = new TreeVo(itemsvo);

        return treeVo;
    }

    /**
     * 删除资源
     * @param resourceVo
     */
    @Override
    @Caching(
            evict = {
                    @CacheEvict(cacheNames  = AdminCacheConstant.RESOURCE_LIST, allEntries = true),
                    @CacheEvict(cacheNames  = AdminCacheConstant.RESOURCE_TREE, allEntries = true)
            }
    )
    public void isEnable(ResourceVo resourceVo) {
        // 判断是否禁用
        if (resourceVo.getDataState().equals("0")){
            String parentResourceNo = resourceVo.getParentResourceNo();
            Resource resource = resourceMapper.selectByResourceNo(parentResourceNo);
            if (resource !=null && resource.getDataState().equals("1")){
                throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
            }
        }
        String resourceNo = resourceVo.getResourceNo();
        resourceMapper.updateDataState(resourceNo,resourceVo.getDataState());
        resourceMapper.updateByParentResourceNo(NoProcessing.processString(resourceNo),resourceVo.getDataState());
    }

    /**
     * 删除资源
     * @param resourceNo
     */
    @Override
    @Caching(
            evict = {
                    @CacheEvict(cacheNames  = AdminCacheConstant.RESOURCE_LIST,allEntries = true),
                    @CacheEvict(cacheNames  = AdminCacheConstant.RESOURCE_TREE, allEntries = true)
            }
    )
    public void deleteResource(String resourceNo) {
        // 判断是否有下级资源
        if (hasChildByResoureId(resourceNo)){
            throw new RuntimeException("存在下级资源,不允许删除");
        }
        // 查询子资源
        Resource resource = resourceMapper.selectByResourceNo(resourceNo);
        // 判断是否启用
        if (resource ==null || resource.getDataState().equals(SuperConstant.DATA_STATE_0)){
           throw new RuntimeException("菜单启用状态，不能删除");
        }
        resourceMapper.deleteResource(resourceNo);
    }

    private boolean hasChildByResoureId(String resourceNo) {
        // 查询子资源
        int result = resourceMapper.hasChildByResoureId(resourceNo);
        return result>0 ? true : false;
    }
    /**
     * 修改资源
     * @param resourceDto
     * @return
     */
    @Override
    @Caching(
            evict = {
                    @CacheEvict(cacheNames  = AdminCacheConstant.RESOURCE_LIST,allEntries = true),
                    @CacheEvict(cacheNames  = AdminCacheConstant.RESOURCE_TREE,allEntries = true)
            }
    )
    public void updateDept(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        int flag = resourceMapper.updateByPrimaryKey(resource);
        if (flag==0){
            throw new RuntimeException("修改失败");
        }
    }



    private String createResourceNo(String parentResourceNo, boolean flag) {

        // 判断是否超过三级
        if (flag && (NoProcessing.processString(parentResourceNo).length() / 3) >= 5) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }

        // 获取父亲的编号
        ResourceDto parentResourceDto = ResourceDto.builder().
                parentResourceNo(parentResourceNo).build();

        // 查询
        List<Resource> childrenResourceList = resourceMapper.resourceList(parentResourceDto);

        // 获取最大编号
        if (EmptyUtil.isNullOrEmpty(childrenResourceList)){
            // 创建编号，且是最大的编号
            return NoProcessing.createNo(parentResourceNo,false);
        }else {
            Long MaxNo = childrenResourceList.stream().map(item -> {
                return Long.valueOf(item.getResourceNo());
            }).max(Comparator.comparing(i -> i)).get();
            return NoProcessing.createNo(String.valueOf(MaxNo),true);
        }
    }

    private void recursionTreeItem(List<TreeItemVo> itemsvo, Resource root, List<Resource> resourceList) {

        // 根节点
        TreeItemVo rootVo = TreeItemVo.builder()
                .id(root.getResourceNo())
                .label(root.getResourceName())
                .build();

        // 跟节点的第一层（儿子们）子节点
        List<Resource> rootChildVo = resourceList.stream()
                .filter(items -> items.getParentResourceNo().equals(root.getResourceNo()))
                .collect(Collectors.toList());
        // 递归第一层儿子下面的儿子们（一层一层的问）
        if (!EmptyUtil.isNullOrEmpty(rootChildVo)) {
            List<TreeItemVo> childList = new ArrayList<>();
            // 递归
            rootChildVo.forEach(items -> {
                recursionTreeItem(childList,items,resourceList);
                log.info("递归："+items.getResourceNo());
            });
            rootVo.setChildren(childList);
        }

        itemsvo.add(rootVo);
    }
}
